package com.yunlinker.hotupdate;

import android.content.Context;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.yunlinker.hotupdate.utils.ExecutorServiceHelper;
import com.yunlinker.hotupdate.utils.FileIOUtils;
import com.yunlinker.hotupdate.utils.FileUtils;
import com.yunlinker.hotupdate.utils.ZipUtils;
import com.yunlinker.manager.HttpManager;
import com.yunlinker.myApp;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import static com.yunlinker.config.WebConfig.AssestRoot;

public class HotUpdateManager {

    private static final String TAG = "HotUpdateManager";

    private static final String updateUrl = "https://ft.dingzhiapp.net/binzang/app/hot/update?clientType=2&sysType=1";

    //assets文件保存目录
    private static String filePath;

    private static final HotUpdateManager instance = new HotUpdateManager();

    private static final boolean isTest = false;

    static {
        if (isSDCardAvailable()) {
            filePath = myApp.getContext().getExternalFilesDir(null).getAbsolutePath();
        } else {
            filePath = myApp.getContext().getFilesDir().getAbsolutePath();
        }
//        filePath = "/sdcard/dsmtest";
    }

    private HotUpdateManager() {

    }

    public static final HotUpdateManager getInstance() {
        return instance;
    }

    public void checkUpdate(final Listener listener) {
        if (isTest) {
            listener.onUpdate(AssestRoot + "index.html");
            return;
        }
        // 先将assets目录下文件拷贝到sdcard
        final Context context = myApp.getContext();
        ExecutorServiceHelper.getInstance().execute(new Runnable() {
            @Override
            public void run() {
                String apiPath = getApiDir();
                File file = new File(apiPath);
                if (!file.exists()) {
                    //将assets文件拷贝到该目录
                    FileUtils.copyAssetsDir(context, "", apiPath);
                    setVersionInfo(0);
                }
                final String result = "file://" + apiPath + File.separator + "index.html";
//                final String result = AssestRoot + "index.html";
                startDealUpdate(new HotUpdateManager.Callback() {
                    @Override
                    public void callback() {
                        notifyLoadUrl(listener, result);
                    }
                });
            }
        });
    }

    private void notifyLoadUrl(final Listener listener, final String url) {
        Log.i(TAG, "notify load web:" + url);
        if (listener != null) {
            ExecutorServiceHelper.getInstance().postToMainLooper(new Runnable() {
                @Override
                public void run() {
                    listener.onUpdate(url);
                }
            });
        }
    }

    private void startDealUpdate(final Callback callback) {
        String result = HttpManager.GET(updateUrl);
        final int versionId = getVersionInfo();
        int targetVersionId = 0;
        String zipUrl = null;
        try {
            JSONObject jsonObject = new JSONObject(result);
            JSONObject data = jsonObject.getJSONObject("data");
            targetVersionId = data.getInt("versionId");
            zipUrl = data.getString("url");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        if (versionId == targetVersionId || TextUtils.isEmpty(zipUrl)) {
            if (callback != null) {
                callback.callback();
            }
            return;
        }
        final int finalTargetVersionId = targetVersionId;
        download(zipUrl, getTempDir(), new OnDownloadListener() {
            @Override
            public void onDownloadSuccess(String filePath) {
                dealUpdate(filePath, new HotUpdateManager.Callback() {
                    @Override
                    public void callback() {
                        setVersionInfo(finalTargetVersionId);
                        if (callback != null) {
                            callback.callback();
                        }
                    }
                });
            }

            @Override
            public void onDownloading(int progress) {

            }

            @Override
            public void onDownloadFailed() {
                if (callback != null) {
                    callback.callback();
                }
            }
        });
    }

    private void dealUpdate(String zipPath, Callback callback) {
        File zipFile = new File(zipPath);
        if (!zipFile.exists()) {
            if (callback != null) {
                callback.callback();
            }
            return;
        }
        String destDir = getTempDir() + File.separator + "zip";
        FileUtils.createOrExistsDir(destDir);
        File destFile = new File(destDir);
        boolean zipSuccess = false;
        try {
            zipSuccess = ZipUtils.unzipFile(zipFile, destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!zipSuccess) {
            if (callback != null) {
                callback.callback();
            }
            return;
        }
        //覆盖
        String apiPath = getApiDir();
        String[] list = destFile.list();
        for (String name : list) {
            String srcPath = destDir + File.separator + name;
            String targetPath = apiPath + File.separator + name;
            File midFile = new File(destDir + File.separator + name);
            if (midFile.isFile()) {
                boolean copy = FileUtils.copyFile(srcPath, targetPath);
                Log.i(TAG, "name=" + name + ";" + copy);
            } else {
                boolean copy = FileUtils.copyDir(srcPath, targetPath);
                Log.i(TAG, "name=" + name + ";" + copy);
            }
        }
        FileUtils.deleteDir(destFile);
        if (callback != null) {
            callback.callback();
        }
    }

    public interface Listener {
        void onUpdate(String indexUrl);
    }

    public static boolean isSDCardAvailable() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }

    public static String getNameFromUrl(String url) {
        return url.substring(url.lastIndexOf("/") + 1);
    }


    public void download(final String url, final String saveDir, final OnDownloadListener listener) {
        Request request = new Request.Builder().url(url).build();
        new OkHttpClient().newCall(request).enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 下载失败
                listener.onDownloadFailed();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                // 储存下载文件的目录
                FileUtils.createOrExistsDir(saveDir);
                try {
                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    File file = new File(saveDir, getNameFromUrl(url));
                    fos = new FileOutputStream(file);
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
                        int progress = (int) (sum * 1.0f / total * 100);
                        // 下载中
                        listener.onDownloading(progress);
                    }
                    fos.flush();
                    // 下载完成
                    listener.onDownloadSuccess(file.getPath());
                } catch (Exception e) {
                    listener.onDownloadFailed();
                } finally {
                    try {
                        if (is != null)
                            is.close();
                    } catch (IOException e) {
                    }
                    try {
                        if (fos != null)
                            fos.close();
                    } catch (IOException e) {
                    }
                }
            }
        });
    }

    private static final String getApiDir() {
        return filePath + File.separator + "test_assets";
    }

    private static final String getTempDir() {
        return filePath + File.separator + "temp";
    }

    private static final String getVersionFile() {
        return getApiDir() + File.separator + "version_test111.txt";
    }

    private interface Callback {
        void callback();
    }

    private interface Callback1<T> {
        void callback(T t);
    }

    private interface OnDownloadListener {
        /**
         * 下载成功
         */
        void onDownloadSuccess(String file);

        /**
         * @param progress 下载进度
         */
        void onDownloading(int progress);

        /**
         * 下载失败
         */
        void onDownloadFailed();
    }

    private HotUpdateInfo getHotUpdateInfo() {
        String versionFile = getVersionFile();
        File file = new File(versionFile);
        if (!file.exists()) {
            return null;
        }
        String s = FileIOUtils.readFile2String(file);
        return JSON.parseObject(s, HotUpdateInfo.class);
    }


    private void setHotUpdateInfo(HotUpdateInfo hotUpdateInfo) {
        String versionFile = getVersionFile();
        File file = new File(versionFile);
        FileUtils.createOrExistsFile(file);
        FileIOUtils.writeFileFromString(file, JSON.toJSONString(hotUpdateInfo), false);
    }

    private void setVersionInfo(int version) {
        HotUpdateInfo hotUpdateInfo = getHotUpdateInfo();
        if (hotUpdateInfo == null) {
            hotUpdateInfo = new HotUpdateInfo();
        }
        hotUpdateInfo.version = version;
        setHotUpdateInfo(hotUpdateInfo);
    }

    private int getVersionInfo() {
        HotUpdateInfo hotUpdateInfo = getHotUpdateInfo();
        return hotUpdateInfo == null ? -1 : hotUpdateInfo.version;
    }

    private class HotUpdateInfo {
        public int version;
    }
}
